package cn.signalpha.modules.shop.service;

import cn.binarywang.wx.miniapp.api.WxMaOrderShippingService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingIsTradeManagedResponse;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import cn.signalpha.common.cache.ConfigCache;
import cn.signalpha.common.cache.ConfigKeys;
import cn.signalpha.common.constant.MsgConstant;
import cn.signalpha.common.dto.ConfigDTO;
import cn.signalpha.common.utils.Assert;
import cn.signalpha.common.utils.SnowflakeUtil;
import cn.signalpha.core.log.exception.ServiceException;
import cn.signalpha.core.log.logger.LoggerUtils;
import cn.signalpha.core.tool.jackson.JsonUtil;
import cn.signalpha.core.tool.support.Kv;
import cn.signalpha.core.tool.utils.*;
import cn.signalpha.modules.base.dto.NoticeDTO;
import cn.signalpha.modules.base.entity.enums.NoticeTypeEnum;
import cn.signalpha.modules.com.entity.User;
import cn.signalpha.modules.com.entity.UserOauth;
import cn.signalpha.modules.com.entity.enums.UserSourceEnum;
import cn.signalpha.modules.com.service.UserOauthService;
import cn.signalpha.modules.com.service.UserService;
import cn.signalpha.modules.com.service.UserWalletService;
import cn.signalpha.modules.pay.enums.PayTypeEnum;
import cn.signalpha.modules.queue.enums.RedisDelayQueueEnum;
import cn.signalpha.modules.queue.utils.RedisDelayQueueUtil;
import cn.signalpha.modules.shop.dto.OrderDTO;
import cn.signalpha.modules.shop.dto.OrderLogisticsDTO;
import cn.signalpha.modules.shop.dto.OrderLogisticsDetailDTO;
import cn.signalpha.modules.shop.entity.*;
import cn.signalpha.modules.shop.entity.enums.LogisticsTypeEnum;
import cn.signalpha.modules.shop.entity.enums.OrderStatusEnum;
import cn.signalpha.modules.shop.event.OrderReceiptEvent;
import cn.signalpha.modules.shop.event.OrderSubmitEvent;
import cn.signalpha.modules.shop.excel.OrderInputExcel;
import cn.signalpha.modules.shop.mapper.OrderMapper;
import cn.signalpha.modules.shop.vo.OrderConfirmVO;
import cn.signalpha.modules.shop.vo.OrderGoodsVO;
import cn.signalpha.modules.shop.vo.OrderVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

import static cn.signalpha.common.cache.CacheNames.EXPIRATION_TIME;
import static cn.signalpha.common.cache.CacheNames.ORDER_CONFIRM;


/**
 * 订单 服务类
 *
 * @author suguangjun
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderService extends ServiceImpl<OrderMapper, Order> {

	private final WxMaService wxMaService;
	private final LoggerUtils loggerUtils;
	private final UserService userService;
	private final GoodsService goodsService;
	private final SnowflakeUtil snowflakeUtil;
	private final SellerService sellerService;
	private final GoodsSkuService goodsSkuService;
	private final UserWalletService walletService;
	private final UserOauthService userOauthService;
	private final CouponUserService couponUserService;
	private final UserAddressService userAddressService;
	private final OrderCouponService orderCouponService;
	private final OrderSettleService orderSettleService;
	private final OrderDetailService orderDetailService;
	private final GoodsCommentService goodsCommentService;
	private final RedisDelayQueueUtil redisDelayQueueUtil;
	private final CityDeliveryService cityDeliveryService;
	private final ApplicationEventPublisher eventPublisher;
	private final OrderLogisticsService orderLogisticsService;
	private final OrderSettlePlaceService orderSettlePlaceService;
	private final OrderLogisticsDetailService orderLogisticsDetailService;

	/**
	 * 自定义分页
	 */
    public IPage<OrderVO> selectOrderPage(IPage<OrderVO> page, Map<String, Object> params) {
        return page.setRecords(baseMapper.selectOrderPage(page, params));
    }

	/**
	 * 自定义Wrapper
	 */
	public QueryWrapper<Order> selectOrderWrapper(Map<String, Object> params) {
		QueryWrapper<Order> wrapper = Wrappers.query();
		wrapper.lambda().in(ObjectUtil.isNotEmpty(params.get("ids")), Order::getId, Func.toLongList(String.valueOf(params.get("ids"))));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("sellerId")), Order::getSellerId, params.get("sellerId"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("userId")), Order::getUserId, params.get("userId"));
		wrapper.lambda().like(ObjectUtil.isNotEmpty(params.get("orderNo")), Order::getOrderNo, params.get("orderNo"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("payStatus")), Order::getPayStatus, params.get("payStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("orderStatus")), Order::getOrderStatus, params.get("orderStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("commentStatus")), Order::getCommentStatus, params.get("commentStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("refundStatus")), Order::getRefundStatus, params.get("refundStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("receiptStatus")), Order::getReceiptStatus, params.get("receiptStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("orderType")), Order::getOrderType, params.get("orderType"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("logisticsType")), Order::getLogisticsType, params.get("logisticsType"));
		wrapper.lambda().like(ObjectUtil.isNotEmpty(params.get("goodsName")), Order::getGoodsName, params.get("goodsName"));
		wrapper.lambda().ge(ObjectUtil.isNotEmpty(params.get("createTimeBegin")), Order::getCreateTime, params.get("createTimeBegin"));
		wrapper.lambda().le(ObjectUtil.isNotEmpty(params.get("createTimeEnd")), Order::getCreateTime, params.get("createTimeEnd"));
		wrapper.lambda().orderByDesc(Order::getId);
		return wrapper;
	}

	/**
	 * 订单金额统计
	 */
	public Double sumByParams(Map<String, Object> params) {
		return sumByParams(params, "goods_price");
	}

	/**
	 * 订单金额统计
	 */
	public Double sumByParams(Map<String, Object> params, String field) {
		QueryWrapper<Order> wrapper = selectOrderWrapper(params);
		wrapper.select(StringUtil.format("ifnull(sum({}),0) as total", field));
		return Double.valueOf(getMap(wrapper).get("total").toString());
	}

	/**
	 * 订单数量统计
	 */
	public long countByParams(Map<String, Object> params) {
		return count(selectOrderWrapper(params));
	}

	/**
	 * 下单人数统计
	 */
	public long countUserNum(Map<String, Object> params) {
		QueryWrapper<Order> wrapper = selectOrderWrapper(params);
		wrapper.lambda().select(Order::getId, Order::getUserId);
		wrapper.groupBy("id, user_id");
		return baseMapper.selectList(wrapper).size();
	}

	/**
	 * 订单号查询
	 */
	public Order getByOrderNo(String orderNo) {
		return this.baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo));
	}

	/**
	 * 购买用户人数
	 */
	public long getBuyerUserCount(Map<String, Object> params) {
		return this.baseMapper.getBuyerUserCount(params);
	}

	/**
	 * 获取某哥店铺下个单的用户
	 */
	public List<Long> selectUserIdBySellerId(Long sellerId) {
		return this.baseMapper.selectUserIdBySellerId(sellerId);
	}

	/**
	 * 订单支付成功
	 */
	public int updateByPaySuccess(List<String> orderNoList, String payType) {
		return baseMapper.updateByPaySuccess(orderNoList, payType);
	}

	/**
	 * Excel导入发货
	 */
	public boolean shippingImport(List<OrderInputExcel> list) {
		return true;
	}

	@CachePut(cacheNames = ORDER_CONFIRM + EXPIRATION_TIME, key = "#userId")
	public OrderConfirmVO putOrderConfirmCache(Long userId, OrderConfirmVO orderConfirmVO) {
		return orderConfirmVO;
	}
	@Cacheable(cacheNames = ORDER_CONFIRM, key = "#userId")
	public OrderConfirmVO getOrderConfirmCache(Long userId) {
		return null;
	}
	@CacheEvict(cacheNames = ORDER_CONFIRM, key = "#userId")
	public void removeOrderConfirmCache(Long userId) {
	}

	/**
	 * 提交订单
	 */
	@Transactional(rollbackFor = Exception.class)
	public List<Order> submitOrder(Long userId, OrderConfirmVO mergerOrder) {
		List<Order> orderList = new ArrayList<>();
		List<OrderSettle> orderSettleList = new ArrayList<>();
		eventPublisher.publishEvent(new OrderSubmitEvent(userId, mergerOrder, orderList, orderSettleList));

		this.saveBatch(orderList);
		orderSettleService.saveBatch(orderSettleList);
		orderDetailService.saveBatch(orderList.stream().flatMap(order -> order.getOrderDetailList().stream()).collect(Collectors.toList()));
		return orderList;
	}

	/**
	 * 修改订单地址
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean updateUserAddress(Serializable id, Long addressId) {
		Order order = baseMapper.selectById(id);
		Assert.isNull(order, MsgConstant.OBJECT_NULL);
		Assert.isTrue(order.getOrderStatus().equals(OrderStatusEnum.PAYED.getStatus()), "当前订单状态不可修改地址");
		long count = orderLogisticsService.count(Wrappers.<OrderLogistics>lambdaQuery().eq(OrderLogistics::getOrderNo, order.getOrderNo()));
		if(count > 0){
			throw new ServiceException("订单已发货不支持修改地址");
		}
		UserAddress userAddress = userAddressService.getById(addressId);
		Assert.isNull(userAddress, "地址不存在");
		Assert.isTrue(order.getUserId().equals(userAddress.getUserId()), "该地址不属于订单用户");
		return updateById(Order.builder().id(order.getId()).logisticsInfo(JsonUtil.toJson(userAddress)).build());
	}

	/**
	 * 取消订单
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean cancelOrder(Serializable id, Long userId) {
		Date now = new Date();
		Order order = baseMapper.selectById(id);
		Assert.isNull(order, MsgConstant.OBJECT_NULL);
		Assert.isTrue(order.getUserId().equals(userId), MsgConstant.UNAUTHORIZED);
		Assert.isTrue(order.getOrderStatus().equals(OrderStatusEnum.UN_PAY.getStatus()), "当前订单状态不可取消订单");

		List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
		Map<Long, Integer> goodsCollect = new HashMap<>(16);
		orderDetailList.stream().collect(Collectors.groupingBy(OrderDetail::getGoodsId)).forEach((goodsId, item) -> {
			goodsCollect.put(goodsId, item.stream().mapToInt(i -> JsonUtil.parse(i.getGoodsDetail(), OrderDTO.DetailDTO.class).getGoodsNum()).sum());
		});
		goodsService.returnStock(goodsCollect);

		Map<Long, Integer> goodsSkuCollect = new HashMap<>(16);
		orderDetailList.stream().collect(Collectors.groupingBy(i -> JsonUtil.parse(i.getGoodsDetail(), OrderDTO.DetailDTO.class).getGoodsSkuId())).forEach((goodsSkuId, item) -> {
			goodsSkuCollect.put(goodsSkuId, item.stream().mapToInt(i -> JsonUtil.parse(i.getGoodsDetail(), OrderDTO.DetailDTO.class).getGoodsNum()).sum());
		});
		goodsSkuService.returnStock(goodsSkuCollect);

		//退优惠券
		orderCouponService.listByOrderNo(order.getOrderNo()).forEach(orderCoupon -> {
			CouponUser couponUser = JsonUtil.parse(orderCoupon.getCouponInfo(), CouponUser.class);
			if(DateUtil.isIn(now, couponUser.getBeginTime(), couponUser.getEndTime())){
				couponUserService.updateById(CouponUser.builder().id(couponUser.getId()).status(0).build());
			}
		});

		//清除sku缓存
		orderDetailList.forEach(orderDetail -> goodsSkuService.removeCacheByGoodsId(orderDetail.getGoodsId()));
		return updateById(Order.builder().id(order.getId()).orderStatus(OrderStatusEnum.CLOSE.getStatus()).updateTime(now).build());
	}

	/**
	 * 确认收货
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean receiptOrder(Serializable id) {
		Order order = baseMapper.selectById(id);
		Assert.isNull(order, MsgConstant.OBJECT_NULL);
		Assert.isTrue(order.getOrderStatus().equals(OrderStatusEnum.SEND_OUT.getStatus()), "当前订单状态不可进行此操作");

		Date date = new Date();
		eventPublisher.publishEvent(new OrderReceiptEvent(order));
		return updateById(Order.builder().id(order.getId()).orderStatus(OrderStatusEnum.SUCCESS.getStatus()).finishTime(date).updateTime(date).build());
	}

	/**
	 * 结算订单
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean settleOrder(Long id) {
//		Date date = new Date();
//		Order order = baseMapper.selectById(id);
//		OrderSettle orderSettle = orderSettleService.getByOrderNo(order.getOrderNo());
//		if(OrderSettleWayEnum.ONE.getCategory() == orderSettle.getSettleWay()){
//			if(orderSettle.getSettleAmount() > 0){
//				sellerService.updateSellerMoney(WalletDTO.builder()
//					.userId(order.getSellerId())
//					.amount(orderSettle.getSettleAmount())
//					.type(WalletTypeEnum.ADD.getType())
//					.sourceId(order.getOrderNo())
//					.sourceType(WalletSourceEnum.ORDER_SETTLE.getType())
//					.remark(WalletSourceEnum.ORDER_SETTLE.getName())
//					.build());
//			}
//			List<OrderSettlePlace> orderSettlePlaceList = orderSettlePlaceService.listByOrderNo(order.getOrderNo());
//			for(OrderSettlePlace orderSettlePlace : orderSettlePlaceList){
//				if(orderSettlePlace.getSettleAmount() > 0){
//					userService.updateUserMoney(WalletDTO.builder()
//						.userId(orderSettlePlace.getUserId())
//						.amount(orderSettlePlace.getSettleAmount())
//						.type(WalletTypeEnum.ADD.getType())
//						.sourceId(order.getOrderNo())
//						.sourceType(Objects.requireNonNull(WalletSourceEnum.instance(orderSettlePlace.getSettleType())).getType())
//						.remark(Objects.requireNonNull(WalletSourceEnum.instance(orderSettlePlace.getSettleType())).getName())
//						.build());
//				}
//				orderSettlePlaceService.updateById(OrderSettlePlace.builder().id(orderSettlePlace.getId()).settleStatus(1).build());
//			}
//
//			updateById(Order.builder().id(id).settleStatus(1).settleTime(date).build());
//			orderSettleService.updateById(OrderSettle.builder().id(orderSettle.getId()).settleStatus(1).settleTime(date).build());
//			return true;
//		}
//		if(OrderSettleWayEnum.TOW.getCategory() == orderSettle.getSettleWay()){
//			IPayGranter iPayGranter = PayGranterBuilder.getGranter(orderSettle.getPayType());
//
//			//分账方
//			List<SettleUserDTO> settleUserList = new ArrayList<>();
//			List<SettleOrderDTO.UserDTO> sellerOrderUserList = new ArrayList<>();
//			settleUserList.add(SettleUserDTO.builder().type(1).relationType("STORE").targetId(orderSettle.getSellerId()).build());
//			sellerOrderUserList.add(SettleOrderDTO.UserDTO.builder().type(1).targetId(orderSettle.getSellerId()).amount(orderSettle.getSettleAmount()).build());
//			List<OrderSettlePlace> orderSettlePlaceList = orderSettlePlaceService.listByOrderNo(order.getOrderNo());
//			orderSettlePlaceList.forEach(orderSettlePlace -> {
//				settleUserList.add(SettleUserDTO.builder().type(2).relationType("STORE").targetId(orderSettlePlace.getUserId()).build());
//				sellerOrderUserList.add(SettleOrderDTO.UserDTO.builder().type(2).targetId(orderSettlePlace.getUserId()).amount(orderSettlePlace.getSettleAmount()).build());
//			});
//			for(SettleUserDTO settleUserDTO : settleUserList){
//				SettleUserVO settleUserVO = iPayGranter.settleUser(settleUserDTO);
//				if(!Objects.equals(StringPool.YES, settleUserVO.getCode())){
//					updateById(Order.builder().id(id).settleStatus(-1).settleTime(date).build());
//					orderSettleService.updateById(OrderSettle.builder().id(orderSettle.getId()).settleStatus(-1).settleRemark(settleUserVO.getMsg()).settleTime(date).build());
//					return false;
//				}
//			}
//			//开始分账
//			SettleOrderVO settleOrderVO = iPayGranter.settleOrder(SettleOrderDTO.builder().settleNo(orderSettle.getId().toString()).payBizNo(orderSettle.getPayBizNo()).userList(sellerOrderUserList).build());
//			if(Objects.equals(StringPool.YES, settleOrderVO.getCode())){
//				updateById(Order.builder().id(id).settleStatus(1).settleTime(date).build());
//				orderSettleService.updateById(OrderSettle.builder().id(orderSettle.getId()).settleStatus(1).settleRemark("结算成功，结算单号：" + settleOrderVO.getMsg()).settleTime(date).build());
//				orderSettlePlaceList.forEach(i -> orderSettlePlaceService.updateById(OrderSettlePlace.builder().id(i.getId()).settleStatus(1).build()));
//				return true;
//			}else{
//				updateById(Order.builder().id(id).settleStatus(-1).settleTime(date).build());
//				orderSettleService.updateById(OrderSettle.builder().id(orderSettle.getId()).settleStatus(-1).settleRemark(settleOrderVO.getMsg()).settleTime(date).build());
//				return false;
//			}
//		}
		return false;
	}

	/**
	 * 评价订单
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean commentOrder(OrderDTO.CommentDTO commentDTO, Long userId) {
		Order order = getById(commentDTO.getId());
		Assert.isNull(order, MsgConstant.OBJECT_NULL);
		Assert.isTrue(order.getUserId().equals(userId), MsgConstant.UNAUTHORIZED);
		Assert.isTrue(order.getOrderStatus().equals(OrderStatusEnum.SUCCESS.getStatus()), "当前订单状态不可评价");
		Assert.isFalse(order.getRefundStatus() == 2, "当前订单状态不可评价");
		Assert.isTrue(order.getCommentStatus() == 0, "请不要重复评价");

		Date dateTime = new Date();
		User user = userService.getById(order.getUserId());
		commentDTO.getDetailList().forEach(commentDetailDTO -> {
			OrderDetail orderDetail = orderDetailService.getById(commentDetailDTO.getId());
			Assert.isNull(orderDetail, "详情记录不存在");
			Assert.isTrue(orderDetail.getRefundStatus() == 0, "明细存在售后商品");

			OrderGoodsVO orderGoodsVO = JsonUtil.parse(orderDetail.getGoodsDetail(), OrderGoodsVO.class);
			GoodsComment goodsComment = new GoodsComment();
			goodsComment.setSellerId(order.getSellerId());
			goodsComment.setGoodsId(orderDetail.getGoodsId());
			goodsComment.setGoodsImg(orderGoodsVO.getImg());
			goodsComment.setGoodsName(orderGoodsVO.getName());
			goodsComment.setGoodsSpec(orderGoodsVO.getGoodsSpec());
			goodsComment.setUserId(user.getId());
			goodsComment.setUserNickName(user.getNickName());
			goodsComment.setUserAvatar(user.getAvatar());
			goodsComment.setIsShow(1);
			goodsComment.setContent(commentDetailDTO.getContent());
			goodsComment.setImg(commentDetailDTO.getImg());
			goodsComment.setGoodsScore(commentDetailDTO.getGoodsScore());
			goodsComment.setCreateTime(dateTime);
			goodsCommentService.save(goodsComment);
			orderDetailService.updateById(OrderDetail.builder().id(orderDetail.getId()).commentStatus(1).build());
			Goods goods = goodsService.getById(orderDetail.getGoodsId());
			goodsService.updateById(Goods.builder().id(goods.getId()).commentNum(goods.getCommentNum() + 1).build());
		});
		return updateById(Order.builder().id(order.getId()).commentStatus(1).updateTime(dateTime).build());
	}

	/**
	 * 订单发货
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean logisticsSave(OrderLogisticsDTO orderLogisticsDTO) {
		Order order = getById(orderLogisticsDTO.getOrderId());
		Assert.isNull(order, MsgConstant.OBJECT_NULL);
		if(!order.getOrderStatus().equals(OrderStatusEnum.PAYED.getStatus())){
			throw new ServiceException(StringUtil.format("订单[{}]状态不可发货", order.getOrderNo()));
		}

		//如果是快递物流，但无需物流，直接发货返回，并更新订单为无需发货
		if(order.getLogisticsType().equals(LogisticsTypeEnum.POST.getType()) && orderLogisticsDTO.getLogisticsType().equals(LogisticsTypeEnum.NOT.getType())){
			uploadShipping(order.getId(), LogisticsTypeEnum.NOT.getType());
			NoticeDTO noticeDTO = new NoticeDTO();
			noticeDTO.setTargetId(order.getId());
			noticeDTO.setType(NoticeTypeEnum.ORDER_SEND_OUT.getType());
			redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
			return updateById(Order.builder().id(order.getId()).logisticsType(LogisticsTypeEnum.NOT.getType()).orderStatus(OrderStatusEnum.SEND_OUT.getStatus()).sendTime(new Date()).build());
		}

		//如果是自提订单，直接发货返回
		if(order.getLogisticsType().equals(LogisticsTypeEnum.PICK.getType())){
			uploadShipping(order.getId(), LogisticsTypeEnum.PICK.getType());
			NoticeDTO noticeDTO = new NoticeDTO();
			noticeDTO.setTargetId(order.getId());
			noticeDTO.setType(NoticeTypeEnum.ORDER_SEND_OUT.getType());
			redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
			return updateById(Order.builder().id(order.getId()).orderStatus(OrderStatusEnum.SEND_OUT.getStatus()).sendTime(new Date()).build());
		}

		//如果是同城配送
		if(order.getLogisticsType().equals(LogisticsTypeEnum.DELIVERY.getType())){
			if(orderLogisticsDTO.getLogisticsType() == 1){
				cityDeliveryService.pushOrder(order);
			}
			uploadShipping(order.getId(), LogisticsTypeEnum.DELIVERY.getType());
			NoticeDTO noticeDTO = new NoticeDTO();
			noticeDTO.setTargetId(order.getId());
			noticeDTO.setType(NoticeTypeEnum.ORDER_SEND_OUT.getType());
			redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
			return updateById(Order.builder().id(order.getId()).orderStatus(OrderStatusEnum.SEND_OUT.getStatus()).sendTime(new Date()).build());
		}

		//全部发货
		if(orderLogisticsDTO.getType() == 1){
			List<OrderLogisticsDetailDTO> detailList = new ArrayList<>();
			orderDetailService.listByOrderNo(order.getOrderNo()).forEach(orderDetail -> {
				OrderLogisticsDetailDTO orderLogisticsDetailDTO = new OrderLogisticsDetailDTO();
				orderLogisticsDetailDTO.setOrderDetailId(orderDetail.getId());
				orderLogisticsDetailDTO.setGoodsNum(orderDetail.getGoodsNum() - (orderDetail.getLogisticsNum() + orderDetail.getRefundNum()));
				if(orderLogisticsDetailDTO.getGoodsNum() > 0){
					detailList.add(orderLogisticsDetailDTO);
				}
			});
			orderLogisticsDTO.setDetailList(detailList);
		}
		if(CollectionUtil.isEmpty(orderLogisticsDTO.getDetailList())){
			throw new ServiceException(StringUtil.format("订单[{}]请选择要发货的明细数据", order.getOrderNo()));
		}

		List<OrderLogisticsDetail> orderLogisticsDetailList = new ArrayList<>();
		orderLogisticsDTO.getDetailList().forEach(orderLogisticsDetailDTO -> {
			OrderDetail orderDetail = orderDetailService.getById(orderLogisticsDetailDTO.getOrderDetailId());
			Assert.isNull(orderDetail, StringUtil.format("订单[{}]明细存在识别错误数据", order.getOrderNo()));
			Integer goodsNum = orderLogisticsDetailDTO.getGoodsNum();
			if(ObjectUtil.isEmpty(goodsNum) || goodsNum <= 0){
				throw new ServiceException(StringUtil.format("订单[{}]请选择正确的发货数量", order.getOrderNo()));
			}
			if(goodsNum > (orderDetail.getGoodsNum() - (orderDetail.getLogisticsNum() + orderDetail.getRefundNum()))){
				throw new ServiceException(StringUtil.format("订单[{}]明细存在超出可发货数量数据", order.getOrderNo()));
			}

			OrderLogisticsDetail orderLogisticsDetail = new OrderLogisticsDetail();
			orderLogisticsDetail.setOrderNo(order.getOrderNo());
			orderLogisticsDetail.setGoodsId(orderDetail.getGoodsId());
			orderLogisticsDetail.setGoodsNum(orderLogisticsDetailDTO.getGoodsNum());
			orderLogisticsDetail.setGoodsDetail(orderDetail.getGoodsDetail());
			orderLogisticsDetailList.add(orderLogisticsDetail);

			//增加发货数量
			orderDetailService.removeCacheByOrderNo(order.getOrderNo());
			orderDetailService.updateById(OrderDetail.builder().id(orderDetail.getId()).logisticsNum(orderDetail.getLogisticsNum() + goodsNum).build());
		});

		OrderLogistics orderLogistics = new OrderLogistics();
		orderLogistics.setOrderNo(order.getOrderNo());
		orderLogistics.setLogisticsId(orderLogisticsDTO.getLogisticsId());
		orderLogistics.setLogisticsNo(orderLogisticsDTO.getLogisticsNo());
		orderLogistics.setCreateTime(new Date());
		orderLogisticsService.save(orderLogistics);
		orderLogisticsDetailList.forEach(orderLogisticsDetail -> {
			orderLogisticsDetail.setLogisticsId(orderLogistics.getId());
		});
		orderLogisticsDetailService.saveBatch(orderLogisticsDetailList);
		orderLogisticsService.removeCacheByOrderNo(order.getOrderNo());

		//判断订单是部分发货还是全部发货
		List<OrderDetail> orderDetailList = orderDetailService.listByOrderNo(order.getOrderNo());
		int goodsNum = orderDetailList.stream().mapToInt(OrderDetail::getGoodsNum).sum();
		int refundNum = orderDetailList.stream().mapToInt(OrderDetail::getRefundNum).sum();
		int logisticsNum = orderDetailList.stream().mapToInt(OrderDetail::getLogisticsNum).sum();
		if(goodsNum == (refundNum + logisticsNum)){
			uploadShipping(order.getId(), LogisticsTypeEnum.POST.getType());
			updateById(Order.builder().id(order.getId()).orderStatus(OrderStatusEnum.SEND_OUT.getStatus()).sendTime(new Date()).build());
		}

		//推送消息
		NoticeDTO noticeDTO = new NoticeDTO();
		noticeDTO.setTargetId(orderLogistics.getId());
		noticeDTO.setType(NoticeTypeEnum.ORDER_SEND_OUT.getType());
		redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
		return true;
	}

	/**
	 * 小程序发货信息录入
	 */
	public void uploadShipping(Serializable id, Integer logisticsType) {
		Order order = baseMapper.selectById(id);
		OrderSettle orderSettle = orderSettleService.getByOrderNo(order.getOrderNo());
		if(orderSettle.getPayType().equals(PayTypeEnum.WX_PAY.getType()) ||
			orderSettle.getPayType().equals(PayTypeEnum.WX_PAY_V3.getType()) ||
			orderSettle.getPayType().equals(PayTypeEnum.JOIN_PAY_WX.getType())){
			if(orderSettle.getPayAmount() > 0 && StringUtil.isNoneBlank(orderSettle.getPayBizNo())){
				ConfigDTO.WxMaDTO config = ConfigCache.getObject(ConfigKeys.WX_MA, ConfigDTO.WxMaDTO.class);
				UserOauth userOauth = userOauthService.getByUserIdAndSourceAndAppId(order.getUserId(), UserSourceEnum.WECHAT_MINI_APP.getValue(), config.getAppId());
				if(ObjectUtil.isNotEmpty(userOauth)){
					try {
						WxMaOrderShippingService wxMaOrderShippingService = wxMaService.getWxMaOrderShippingService();
						WxMaOrderShippingIsTradeManagedResponse wxMaOrderShippingIsTradeManagedResponse = wxMaOrderShippingService.isTradeManaged(userOauth.getAppId());
						if(wxMaOrderShippingIsTradeManagedResponse.getTradeManaged()){
							//构建上传的参数
							UserAddress userAddress = JsonUtil.parse(order.getLogisticsInfo(), UserAddress.class);
							List<ShippingListBean> shippingListBeanList = new LinkedList<>();
							if(logisticsType.equals(LogisticsTypeEnum.POST.getType())){
								orderLogisticsDetailService.selectOrderLogisticsDetailList(Kv.create().set("orderNo", order.getOrderNo())).forEach(orderLogisticsDetailVO -> {
									ShippingListBean shippingListBean = ShippingListBean.builder()
										.trackingNo(orderLogisticsDetailVO.getLogisticsNo())
										.expressCompany(orderLogisticsDetailVO.getLogisticsCodeWx())
										.itemDesc(JsonUtil.parse(orderLogisticsDetailVO.getGoodsDetail(), OrderGoodsVO.class).getName())
										.contact(ContactBean.builder().receiverContact(DesensitizedUtil.mobilePhone(userAddress.getMobile())).build())
										.build();
									shippingListBeanList.add(shippingListBean);
								});
							}else{
								ShippingListBean shippingListBean = ShippingListBean.builder()
									.trackingNo(StringPool.EMPTY)
									.expressCompany(StringPool.EMPTY)
									.itemDesc(StrUtil.sub(order.getGoodsName(), 0, 100))
									.contact(ContactBean.builder().receiverContact(DesensitizedUtil.mobilePhone(userAddress.getMobile())).build())
									.build();
								shippingListBeanList.add(shippingListBean);
							}

							int deliveryMode = 1;
							int wxLogisticsType = 3;
							if(logisticsType.equals(LogisticsTypeEnum.POST.getType())){
								deliveryMode = 2;
								wxLogisticsType = 1;
							}else if(logisticsType.equals(LogisticsTypeEnum.PICK.getType())){
								wxLogisticsType = 4;
							}else if(logisticsType.equals(LogisticsTypeEnum.DELIVERY.getType())){
								wxLogisticsType = 2;
							}
							wxMaOrderShippingService.upload(WxMaOrderShippingInfoUploadRequest.builder()
								.orderKey(OrderKeyBean.builder().orderNumberType(2).transactionId(orderSettle.getPayBizNo()).build())
								.logisticsType(wxLogisticsType)
								.deliveryMode(deliveryMode)
								.isAllDelivered(true)
								.shippingList(shippingListBeanList)
								.payer(PayerBean.builder().openid(userOauth.getOpenId()).build())
								.uploadTime(DateUtil.format(new Date(), DatePattern.UTC_WITH_XXX_OFFSET_PATTERN))
								.build());
						}
					} catch (WxErrorException e) {
						log.error("微信发货信息录入失败：{}", e.getMessage());
					}
				}
			}
		}
	}

}
